Matrices
'''¿Qué son las matrices?''' Las matrices no son una estructura propia de Python. Simplemente, una matriz es una lista de listas que nosotros interpretamos desde el punto de vista matemático. Es decir, estructura la estructura m = [[1,2], [3,4]] nosotros la interpretamos como la matriz 2x2 cuya↵primera fila es (1,2) y cuya segunda fila es (3,4), pero esto no deja de ser una↵interpretación En [1]: m = [[1,2], [3,4]] m La forma de acceder a los elementos de la matriz es utilizando su nombre e indicando los 2 subíndices que van en los corchetes y son las filas y las columnas. Ejemplo '''Declarar una Matriz''' import numpy as np matrix_aux = [[1,2,3], [4,5,6]] m = np.array(matrix_aux) l = np.zeros((3, 3)) print(l) [[ 0. 0. 0.] [ 0. 0. 0.] [ 0. 0. 0.]] l = np.ones([3,3]) print(l) [[ 1. 1. 1.] [ 1. 1. 1.] [ 1. 1. 1.]] l = np.diag([1,1,1]) print(l) [[1 0 0] [0 1 0] [0 0 1]] '''Acceder a elementos de la matriz''' print(m[1,1]) print(m[:,2]) print(m[0,:]) print(m[0,::-1]) '''Sumar de elementos de la matriz''' Sumar todos los elementos print(m.sum()) Sumar de una fila de la matriz print(m[0,:].sum()) '''Aplanar una matriz''' print( m.flatten() ) [1 2 3 4 5 6] '''Concatenación de matrices''' print( np.concatenate((m,m), axis=0) ) [[1 2 3] [4 5 6] [1 2 3] [4 5 6]] print( np.concatenate((m,m), axis=1) ) [[1 2 3 1 2 3] [4 5 6 4 5 6]] '''Operaciones aritméticas''' Tienen la peculiaridad de broadcasting o redifusión, que consite en que si una de las dimensiones a la hora de aplicar la operación no tiene una dimensión correcta pero es unitaria se redifusiona hasta completar la matriz. m = np.array([[1,2,3], [4,5,6]]) v = np.array([[1,2,3]]) print( m * v) [[ 1 4 9] [ 4 10 18] Esto puede verse gráficamente en el ejemplo siguiente. Sencillamente, las matrices son listas, dentro de otro lista. Sí, así es, podemos decir que es una lista bidimensional, 2x2. Supongamos que tenemos la matriz: [[4,3], [9,3]]. La primera fila de esta matriz es (4,3) y la segunda (9,3). En Python nos quedaría algo así: a = [[4,3], [9,3]] imprimir (a) [[4, 3], [9, 3]] Sabiendo todo esto, podemos crear nuestras propias formas de generar matrices: def newMatrix(f,c,n): matriz = [] for i in range(f): a = [n]*c matriz.append(a) return matriz newMatrix(3, 5, 1) [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]] Esta función nos permite generar todas las matrices que queramos. La función recibe tres argumentos: f = filas de la matriz, c = columnas de la matriz, n = los elementos de la matriz. En este caso, el tercer argumento es 1, y por ello todos los elementos de la matriz están determinados con el valor 1. '''Operaciones matemáticas con matrices:''' Ahora, algunas operaciones matemáticas que podemos manejar sobre nuestras matrices: Como por la operación más básica, la suma. En la siguiente imagen se muestra el proceso de suma que se lleva a cabo entre dos matrices. Muy fácil, es algo muy predecible. Se suma cada elemento de las dos matrices donde sus índices son los mismos. Veamos como podemos hacer esto en código: def sumaMatriz(A,B): # Obtenemos las dimensiones de la matriz numFilasA = len(A) numFilasB = len(B) numColumnasA = len(A[0]) numColumnasB = len(B[0]) if numFilasA numFilasB and numColumnasA numColumnasB: C = newMatrix(numFilasA, numColumnasA, 0) # Creamos una matriz for i in range(numFilasA): for j in range(numColumnasA): # En la nueva matriz plasmamaos los resultados C[i][j] = A[i][j] + B[i][j] # Retornamos la matriz con los resultados return C suma = sumaMatriz([[1,2,3],[7,8,9],[13,14,15]], [[4,5,6],[10,11,12],[16,17,18]]) print(suma) [[5, 7, 9], [17, 19, 21], [29, 31, 33]] Podemos tomar la base de esta función para realizar otras operaciones matemáticas, solo debemos cambiar el signo. def multiplicacionMatriz(A,B): # Obtenemos las dimensiones de la matriz numFilasA = len(A) numFilasB = len(B) numColumnasA = len(A[0]) numColumnasB = len(B[0]) if numFilasA numFilasB and numColumnasA numColumnasB: C = newMatrix(numFilasA, numColumnasA, 0) # Creamos una matriz for i in range(numFilasA): for j in range(numColumnasA): # En la nueva matriz plasmamaos los resultados C[i][j] = A[i][j] * B[i][j] # Retornamos la matriz con los resultados return C multiplicacionMatriz([[1,2,3],[7,8,9],[13,14,15]], [[4,5,6],[10,11,12],[16,17,18]]) [[4, 10, 18], [70, 88, 108], [208, 238, 270]] Como pueden ver, es muy fácil. Solo debemos tener un poco de lógica al momento de recorrer la matriz. '''Representando una matriz:''' Para terminar, vamos a crear una función que nos permite visualizar las matrices de una forma más ordenada y limpia. Veamos como hacerlo: def show_matrix(M): """ Imprime los valores almacenados en la matriz """ filas = len(M) columnas = len(M[0]) for i in range(filas): for j in range(columnas): # Imprime de una forma elegante la matriz print("| {0} ".format(M[i][j]), sep=',', end='') print('|\n') La función recibe la matriz como argumento, extrae sus dimensiones (filas y columnas) y se muestra cada elemento, espacios específicos y el caracter | para separar los valores. Probemos la función: a = [[1,2,3],[7,8,9],[4,5,6]] show_matrix(a) | 1 | 2 | 3 | | 7 | 8 | 9 | | 4 | 5 | 6 | Veamos como se ve la matriz de suma: show_matrix(suma) | 5 | 7 | 9 | | 17 | 19 | 21 | | 29 | 31 | 33 | '''Matrices y listas''' Cuando necesitamos manejar muchos datos, generalmente hay soluciones más efectivas que tener muchas variables. Por ejemplo, si hay que guardar 100 números, suele ser más eficiente almacenar esos 100 datos "juntos", formando una "matriz", en vez de usar 100 variables distintas. La palabra "matriz" es una traducción del inglés "array". Algunos autores lo traducen alternativamente como tabla, vector o incluso "arreglo". Normalmente, en una matriz podremos acceder individualmente a cada uno de sus elementos usando corchetes: el primer dato sería algo como "datos[0]", y el último de 10 elementos sería "datos[9]". Vamos a ver un ejemplo que prepare un array con 6 elementos, nos pida 6 datos y luego los muestre en orden contrario al que se han introducido: datos = [0,0,0,0,0,0] for i in range(1,7): datos[i-1] = int( input( "Dime el dato numero {}: ".format(i) )) print ("Los datos al reves son: ") for i in range(6,0,-1): print ( datos[i-1] ) En Python, los arrays pueden ir aumentando de tamaño (comparado con otros lenguajes de programación, en este sentido se parecen más a lo que en muchos lenguajes de programación se conoce como "listas"). Así, podemos partir de un array vacío e ir añadiendo elementos con ".append": datos = [] for i in range(1,7): nuevoDato = int( input( "Dime el dato numero {}: ".format(i) )) datos.append(nuevoDato) print ("Los datos al reves son: ") for i in range(6,0,-1): print ( datos[i-1] ) Nota: No podemos crear el array vacío con "datos = []" y luego dar valor a un elemento con "datos[0]=5", porque obtendríamos un mensaje de error que nos avisa de que nos hemos salido del rango de los datos. Deberemos reservar todas las posiciones (como en el primer ejemplo) o bien usar ".append" (como en el segundo). También podemos saber la cantidad de datos con "len(datos)", eliminar un elemento con ".remove", insertar en una cierta posición con ".insert", o añadir toda una nueva lista de datos con "+", como en este ejemplo: datos = [5,6,7,8,9] for i in range(0,5): print ( datos[i] , end=" " ) print() datos.remove(6) for i in range(0, len(datos)): print ( datos[i] , end=" " ) print() datos[0]=-2 for i in range(0,len(datos)): print ( datos[i] , end=" " ) print() datos.insert(1,23) for i in range(0,len(datos)): print ( datos[i] , end=" " ) print() datos = datos + [31,32,33] for i in range(0,len(datos)): print ( datos[i] , end=" " ) print() Cuyo resultado sería 5 6 7 8 9 5 7 8 9 -2 7 8 9 -2 23 7 8 9 -2 23 7 8 9 31 32 33 Si un array va a contener muchos más datos, puede resultar incómodo eso de dar los valores iniciales uno por uno, y quizá no podamos emplear ".append" si los valores no los vamos a recibir exactamente en orden. En ese caso, se puede inicializar el array usando una orden "for" dentro de los corchetes, así: datos = [0 for x in range(20)] for i in range(0,len(datos)): datos[i] = int( input( "Dime el dato numero {}: ".format(i+1) )) print ("Los datos al reves son: ") for i in range(len(datos),0,-1): print ( datos[i-1] ) Una forma más avanzada de crear un (falso) array vacío, para luego irlo rellenando, es usar unas llaves vacías, como en "datos = { }", aunque esto tiene un significado ligeramente distinto (estaríamos creando un "diccionario", como veremos más adelante): datos = { } for i in range(1,7): datos[i-1] = int( input( "Dime el dato numero {}: ".format(i) )) print ("Los datos al reves son: ") for i in range(6,0,-1): print ( datos[i-1] ) '''Ejemplos de matrices:'''